﻿using Mapster;
using SqlSugar;
using Zhp.IService.Design;
using Zhp.Model.Design;
using Zhp.SqlSugar.Entity;

namespace Zhp.Service.Design
{
    public class DesignTableService : IDesignTableService
    {
        private const string DesignPrefixConst = "Design_Instance";
        ISqlSugarClient _dbContext;
        public DesignTableService(ISqlSugarClient dbContext)
        {
            _dbContext = dbContext;
        }

        public async Task<List<DesignTableModel>> Query()
        {
            var tables = _dbContext.DbMaintenance.GetTableInfoList(false);
            var list = tables.Where(x => x.DbObjectType == DbObjectType.Table && x.Name.StartsWith(DesignPrefixConst));

            return await Task.FromResult(list.Adapt<List<DesignTableModel>>());
        }

        public async Task<bool> Create(DesignTableEdit create)
        {
            var type = GetDynamicType(create);

            //创建表
            _dbContext.CodeFirst.InitTables(type);

            return await Task.FromResult(true);
        }

        public async Task<bool> Update(DesignTableEdit update)
        {
            string tableName = GetTableName(update.Name);

            _dbContext.Utilities.RemoveCacheByLikeKey<Type>(tableName);

            var type = GetDynamicType(update);

            //创建表
            _dbContext.CodeFirst.InitTables(type);

            return await Task.FromResult(true);
        }

        public async Task<bool> TableRename(DesignTableRename update)
        {
            bool result = _dbContext.DbMaintenance.RenameTable(update.OldTableName, GetTableName(update.NewTableName));

            return await Task.FromResult(result);
        }

        public async Task<bool> Delete(string tableName)
        {
            bool result = false;
            if (_dbContext.DbMaintenance.IsAnyTable(tableName, false))
            {
                result = _dbContext.DbMaintenance.DropTable(tableName);
            }
            return await Task.FromResult(result);
        }

        /// <summary>
        /// 操作数据时使用
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public Type GetDynamicType(string tableName)
        {
            var baseType = typeof(BaseEntity<long>);
            var typeBilder = _dbContext.DynamicBuilder().CreateClass(tableName, new SugarTable()
            {
                TableName = tableName,
            }
            , baseType
            );

            var columns = _dbContext.DbMaintenance.GetColumnInfosByTableName(tableName);

            //排除掉父类中的属性，否则会重复
            var props = baseType.GetProperties().Select(x => x.Name);
            columns = columns.Where(x => !props.Contains(x.DbColumnName)).ToList();

            foreach (var item in columns)
            {
                typeBilder.CreateProperty(item.DbColumnName, GetTypeFromName(item.DataType), new SugarColumn
                {
                    IsPrimaryKey = item.IsPrimarykey,
                    ColumnName = item.DbColumnName,
                    Length = item.Length,
                    DecimalDigits = item.DecimalDigits,
                    ColumnDescription = item.ColumnDescription,
                    IsNullable = item.IsNullable,
                });
            }
            
            //缓存Key 表名+字段名称相加
            typeBilder.WithCache();

            //创建类
            var type = typeBilder.BuilderType();

            return type;
        }

        /// <summary>
        /// 创建表是使用
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public Type GetDynamicType(DesignTableEdit p)
        {
            string tableName = GetTableName(p.Name);
            var typeBilder = _dbContext.DynamicBuilder().CreateClass(tableName, new SugarTable()
            {
                TableName = tableName,
                TableDescription = p.Description,
            }
            , typeof(BaseEntity<long>)
            );

            //可以循环添加列
            foreach (var item in p.ColumnList)
            {
                typeBilder.CreateProperty(item.ColumnName, GetTypeFromName(item.DataType), new SugarColumn
                {
                    IsPrimaryKey = item.IsPrimarykey,
                    ColumnName = item.ColumnName,
                    OldColumnName = item.OldColumnName,
                    Length = item.Length.HasValue ? item.Length.Value : 0,
                    DecimalDigits = item.DecimalDigits.HasValue ? item.DecimalDigits.Value : 0,
                    ColumnDescription = item.ColumnDescription,
                    IsNullable = item.IsNullable,
                });
            }

            //缓存Key 表名+字段名称相加
            typeBilder.WithCache();

            //创建类
            var type = typeBilder.BuilderType();

            return type;
        }

        /// <summary>
        /// 处理数据库与C#对应类型
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        public Type GetTypeFromName(string dataType)
        {
            var list = QueryDataTypeSelect();
            var obj = list.First(x => x.Code == dataType);
            if(obj != null)
            {
                return Type.GetType(obj.Type);
            }
            else
            {
                return typeof(string);
            }
        }

        public List<DesignColumnDataType> QueryDataTypeSelect()
        {
            var list = new List<DesignColumnDataType>
            {
                new() 
                {
                    Code = "nvarchar",
                    Type = typeof(string).FullName,
                    Description = "字符串"
                },
                new() 
                {
                    Code = "int",
                    Type = typeof(int).FullName,
                    Description = "整数"
                },
                new() 
                {
                    Code = "bigint",
                    Type = typeof(long).FullName,
                    Description = "长整数"
                },
                new() 
                {
                    Code = "bit",
                    Type = typeof(bool).FullName,
                    Description = "布尔类型"
                },
                new() 
                {
                    Code = "decimal",
                    Type = typeof(decimal).FullName,
                    Description = "小数类型"
                },
                new()
                {
                    Code = "datetime",
                    Type = typeof(DateTime?).FullName,
                    Description = "日期类型"
                },
            };
            return list;
        }

        private string GetTableName(string tableName)
        {
            if (!tableName.StartsWith(DesignPrefixConst))
            {
                return $"{DesignPrefixConst}_{tableName}";
            }
            else
            {
                return tableName;
            }
        }


        public async Task<List<DesignColumnModel>> QueryColumn(string tableName)
        {
            var columns = _dbContext.DbMaintenance.GetColumnInfosByTableName(tableName, false);

            var list = new List<DesignColumnModel>();

            foreach (var column in columns)
            {
                var item = column.Adapt<DesignColumnModel>();
                item.ColumnName = column.DbColumnName;

                ConvertLength(item);

                ConvertDigits(item);

                list.Add(item);
            }

            return await Task.FromResult(list);
        }

        private void ConvertLength(DesignColumnModel column)
        {
            switch (column.DataType)
            {
                case "int":
                case "bigint":
                    column.Length = null;
                    return;
                case "date":
                case "datetime":
                    column.Length = null;
                    return;
                default:
                    break;
            }
        }

        private void ConvertDigits(DesignColumnModel column)
        {
            if (column.DataType != "decimal" || column.DataType != "datetime")
            {
                column.DecimalDigits = null;
            }
        }
    }
}
